<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    /*
        1. 实例成员
            constructor - 相当于把属性添加到 实例上
     */
    class Person {
        constructor() {
            // 这个例子先使用对象包装类型定义一个字符串 
            // 为的是在下面测试两个对象的相等性 
            this.name = new String('Jack');
            this.sayName = () => {
                console.log('this', this)
                console.log(this.name)
            };
            this.nicknames = ['Jake', 'J-Dog']
        }
    }

    let p1 = new Person(),
        p2 = new Person();
    p1.sayName(); // Jack
    p2.sayName(); // Jack
    console.log(p1.name === p2.name);
    console.log(p1.sayName === p2.sayName);
    console.log(p1.nicknames === p2.nicknames); // false
    p1.name = p1.nicknames[0];
    p2.name = p2.nicknames[1];
    p1.sayName(); // Jake 
    p2.sayName(); // J-Dog

    // 自行添加
    p1.count = 10;
    console.log(p1.count)

    /*
        2. 原型方法与访问器
            - 在类中定义的方法相等于在原型上
            -  Person2.prototype上
     */
    console.log('---2---')

    class Person2 {
        constructor() {
            this.locate = () => console.log('instance-实例')
        }

        // 在类块中定义的所有内容都会定义在类的原型上
        // Person2.prototype上
        locate() {
            console.log('prototype-原型')
        }

        // 也支持获取和设置访问器
        set name(newName) {
            this.name_ = newName
        }

        get name() {
            return this.name_;
        }

        // 不行
        // name:'Jack'
    }

    let p2_1 = new Person2();
    p2_1.locate();  // instance-实例
    Person2.prototype.locate(); // prototype-原型
    console.log(p2_1)

    /*
        2.1 同理,也支持动态方法名和Symbol方法名
     */


    /*
        3.静态类方法
     */
    // 3.1 多个位置演示
    console.log('---3---')

    class Person3 {
        constructor() {
            // 添加到不同的实例上
            this.locate = () => console.log('instance', this)
        }

        // 定义在类的原型对象上
        locate() {
            console.log('prototype', this)
        }

        // 定义在类本身上
        static locate() {
            console.log('class', this)
        }
    }

    let p = new Person3()
    p.locate();
    Person3.prototype.locate();
    Person3.locate();

    // 3.2 静态方法非常适合作为实例工厂
    class Person3_2 {
        constructor(age) {
            this.age_ = age;
        }

        sayAge() {
            console.log(this.age_)
        }

        static create() {
            // 使用随机年龄创建并返回一个Person实例
            return new Person3_2(Math.floor(Math.random() * 100))
        }
    }

    console.log(Person3_2.create())

    /*
        4.非函数原型和类方法
     */

    /*
        5.迭代器有生成器方法
     */
    // 5.1简单使用
    console.log('---5---')

    class Person5_1 {
        // 在原型上定义生成器方法
        * createNicknameIterator() {
            yield 'Jack';
            yield 'Jake';
            yield 'J-Dog'
        }

        // 在类上定义生成器方法
        static* createJobIterator() {
            yield 'Butcher'
            yield 'Baker'
            yield "Cooker"
        }
    }

    let jobIter = Person5_1.createJobIterator();
    console.log(jobIter.next())
    console.log(jobIter.next())
    console.log(jobIter.next())
    let p5_1 = new Person5_1();
    let nickNameIter = p5_1.createNicknameIterator();
    console.log(nickNameIter.next())
    console.log(nickNameIter.next())
    console.log(nickNameIter.next())


    // 5.2 可以通过添加一个默认的迭代器,把类实例编程可迭代对象
    console.log('---5_2---')
    class Person5_2 {
        constructor() {
            this.nicknames = ['Jack', 'Tom', 'Smith']
        }

        * [Symbol.iterator]() {
            yield* this.nicknames.entries();
        }
    }

    let p5_2 = new Person5_2();
    for (let [index, nickname] of p5_2) {
        console.log(nickname)
    }

</script>
</body>
</html>